#include "lib/print.h"
#include "proc/cpu.h"
#include "mem/mmap.h"
#include "mem/vmem.h"
#include "syscall/syscall.h"
#include "syscall/sysnum.h"
#include "syscall/sysfunc.h"

// 系统调用跳转
static uint64 (*syscalls[])(void) = {
    [SYS_brk]           sys_brk,
    [SYS_mmap]          sys_mmap,
    [SYS_munmap]        sys_munmap,
    [SYS_fork]          sys_fork,
    [SYS_wait]          sys_wait,
    [SYS_exit]          sys_exit,
    [SYS_sleep]         sys_sleep,

    // 添加系统调用
    [SYS_exec]         sys_exec,
    [SYS_open]         sys_open,
    [SYS_close]        sys_close,
    [SYS_read]         sys_read,
    [SYS_write]        sys_write,
    [SYS_lseek]        sys_lseek,
    [SYS_dup]          sys_dup,
    [SYS_fstat]        sys_fstat,
    [SYS_getdir]       sys_getdir,
    [SYS_mkdir]        sys_mkdir,
    [SYS_chdir]        sys_chdir,
    [SYS_link]         sys_link,
    [SYS_unlink]       sys_unlink,
};

// 系统调用
void syscall()
{
    uint64 syscall_id;
    proc_t* proc = myproc();  // 获取当前进程信息

    // 获取系统调用号
    syscall_id = proc->tf->a7;

    // 检查系统调用号的有效性
    if (syscall_id < 0 || syscall_id >= sizeof(syscalls) / sizeof(syscalls[0]) || syscalls[syscall_id] == NULL) {
        printf("Invalid syscall: %d\n", syscall_id);
        proc->tf->a0 = -1;  // 返回错误码
        return;
    }

    // 调用相应的系统调用处理函数
    uint64 result = syscalls[syscall_id]();  // 调用相应的系统调用处理函数

    // 设置返回值到 a0 寄存器
    proc->tf->a0 = result;

}

/*
    其他用于读取传入参数的函数
    参数分为两种,第一种是数据本身,第二种是指针
    第一种使用tf->ax传递
    第二种使用uvm_copyin 和 uvm_copyinstr 进行传递
*/

// 读取 n 号参数,它放在 an 寄存器中
static uint64 arg_raw(int n)
{   
    proc_t* proc = myproc();
    switch(n) {
        case 0:
            return proc->tf->a0;
        case 1:
            return proc->tf->a1;
        case 2:
            return proc->tf->a2;
        case 3:
            return proc->tf->a3;
        case 4:
            return proc->tf->a4;
        case 5:        
            return proc->tf->a5;
        default:
            panic("arg_raw: illegal arg num");
            return -1;
    }
}

// 读取 n 号参数, 作为 uint32 存储
void arg_uint32(int n, uint32* ip)
{
    *ip = arg_raw(n);
}

// 读取 n 号参数, 作为 uint64 存储
void arg_uint64(int n, uint64* ip)
{
    *ip = arg_raw(n);
}

// 读取 n 号参数指向的字符串到 buf, 字符串最大长度是 maxlen
void arg_str(int n, char* buf, int maxlen)
{
    proc_t* p = myproc();
    uint64 addr;
    arg_uint64(n, &addr);

    uvm_copyin_str(p->pgtbl, (uint64)buf, addr, maxlen);
}